#include <FinalCType/String.h>
#include <FinalCType/List.h>
#include <FinalCType/StringList.h>

#include <SocketUtils.h>
#include <Thread.h>

#include <lib/Log/include/Log.h>

#include <unistd.h>
#include <errno.h>
#include <stdio.h>

#define FinalC_Enum_Define(type)        \
typedef enum type##_enum type;          \
enum type##_enum

typedef void(*FinalC_Enum_Define);


FinalC_Object_Define_Type(ChatRoomChannel);
FinalC_Object_Define_Type(ChatRoom);
FinalC_Object_Define_Type(People);

typedef void (*newPeopleJoin)(People*);
typedef void (*hasPeopleLeave)(People*);


FinalC_Enum_Define(ChatMessageType) {
    CommonMessage,
    ControlMessage,
};

FinalC_Object_Define_Of(ChatRoomChannel) {
    char name[256];
    char index;

    ChatRoom *room;
};

FinalC_Object_Define_Of(ChatRoom) {
    TcpSocket socket;
    SocketAddress address;

    newPeopleJoin join;
    hasPeopleLeave leave;

    List *peoples;
    List *channels;
};

FinalC_Object_Define_Of(People) {
    TcpSocket socket;
    char name[100];

    ChatRoom *room;
};

FinalC_Object_Define(ChatMessage) {
    ChatMessageType type;
    char title[100];
    char body[100];
};

static createThreadHandle(defaultChatRoomWorkThread) {
    People people;
    memcpy(&people, data, sizeof(People));

    ChatRoom *room = people.room;

    // INFO_LOG("-- 用户进入 %s ---", people.name);

    while (1)
    {
        fd_set fds;

        FD_ZERO(&fds);
        FD_SET(people.socket.socket, &fds);

        int ret = select(people.socket.socket + 1, &fds, NULL, NULL, NULL);

        if (ret > 0) {
            if (FD_ISSET(people.socket.socket, &fds)) {
                
                char buffer[1000] = {0};

                int recv = tcpSocketRead(&people.socket, buffer, sizeof(buffer));

                if ((recv == 0 || recv < 0) && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
                    DEBUG_LOG("%s: 数据接收异常，但不被视为远端关闭连接: %d", __func__, errno);
                    usleep(30000);
                    continue;
                } else if (recv <= 0) {
                    DEBUG_LOG("%s: 数据接收异常，将视为远端关闭连接: %d", __func__, errno);
                    room->leave(&people);
                    close(people.socket.socket);

                    String *message = createStringWith_copy_cstr("msg::::服务器提示::::(");
                    message = stringAppend_cstr(message, people.name);
                    message = stringAppend_cstr(message, ")离开聊天室.");


                    List *iter = NULL;
                    list_foreach(iter, room->peoples) {
                        if (iter->data != &people) {
                            tcpSocketWrite(&((People*)iter->data)->socket, message->value, message->len);
                        }
                    }

                    return NULL;
                }

                String *str = createStringWith_cstr(buffer);
                INFO_LOG("--- 收到消息 (%s) ---", str->value);
                if (stringContains_cstr(str, "msg::::")) {
                    
                    List *iter = NULL;
                    list_foreach(iter, room->peoples) {
                        if (iter->data != &people) {
                            tcpSocketWrite(&((People*)iter->data)->socket, buffer, sizeof(buffer));
                        }
                    }
                }

                if (stringContains_cstr(str, "connect::::")) {
                    String *message = createStringWith_copy_cstr("msg::::服务器::::已收到连接请求.");
                    tcpSocketWrite(&people.socket, message->value, message->len);

                    // INFO_LOG("发送消息: %s", message->value);

                    strcpy(people.name, buffer+11);
                    room->join(&people);

                    // 释放 message
                    deleteString(message);
                    
                    String *onlineMessage = createStringWith_size(1000);
                    sprintf(onlineMessage->value, "msg::::服务器::::当前有(%d)人在线.", listLength(room->peoples));
                    tcpSocketWrite(&people.socket, onlineMessage->value, onlineMessage->len);

                    message = createStringWith_copy_cstr("msg::::服务器提示::::(");
                    message = stringAppend_cstr(message, people.name);
                    message = stringAppend_cstr(message, ")进入聊天室.");

                    List *iter = NULL;
                    list_foreach(iter, room->peoples) {
                        if (iter->data != &people) {
                            tcpSocketWrite(&((People*)iter->data)->socket, message->value, message->len);
                        }
                    }

                    list_foreach(iter, room->peoples) {
                        if (iter->data != &people) {
                            tcpSocketWrite(&((People*)iter->data)->socket, onlineMessage->value, onlineMessage->len);
                        }
                    }

                    // 释放 onlineMessage
                    deleteString(onlineMessage);

                    // 释放 buffer
                    deleteString(message);
                }

                destroyString(str);
            }
        }

        // people.room->leave(&people);
    }

    return NULL;
};


static createThreadHandle(defaultPersonWorkThread) {

    People *people = data;
    INFO_LOG("-- 用户进入 %s ---", people->name);

    while (1)
    {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(STDIN_FILENO, &fds);
        FD_SET(people->socket.socket, &fds);

        int ret = select(people->socket.socket+1, &fds, NULL, NULL, NULL);

        if (ret > 0) {
            if (FD_ISSET(STDIN_FILENO, &fds)) {
                String *input = NULL;
                
                bool eof = false;
                while(!eof) {
                    char chr = fgetc(stdin);
                    if (chr == '\n') {
                        eof = true;
                        break;
                    }
                    input = stringAppend_char(input, chr);
                }
                if (input == NULL) {

                    continue;
                }

                if ((input->len > 6) && strncmp(input->value, "/name ",6) == 0) {
                    memset(people->name, 0, 100);
                    strcat(people->name, input->value+6);
                    
                    INFO_LOG("-- 设置用户名称 %s ---", people->name);

                    deleteString(input);
                    continue;
                }

                if ((input->len > 9) && strncmp(input->value, "/connect ", 9) == 0) {
                    char control[20];
                    char host[20];
                    int port;
                    sscanf(input->value, "%s %s %d", control, host, &port);

                    if (setSocketConnectAddress(&people->socket.address, AF_INET, host, port)) {
                        INFO_LOG("--- 尝试连接服务器... ---");
                        if (socketConnect(&people->socket, &people->socket.address, sizeof(people->socket.address))) {
                            char msg[1000] = {"connect::::"};
                            strcat(msg, people->name);
                            tcpSocketWrite(&people->socket, msg, sizeof(msg));
                            people->room->join(people);
                        } else {
                            INFO_LOG("--- 连接失败 ---");
                        }
                    } else {
                        WARNING_LOG("--- 格式错误 ---");
                    }

                    deleteString(input);
                    continue;
                }

                String *message = createStringWith_copy_cstr("msg::::");
                message = stringAppend_cstr(message, people->name);
                message = stringAppend_cstr(message, "::::");
                message = stringAppend(message, input);
                // message

                tcpSocketWrite(&people->socket, message->value, message->len);

                INFO_LOG("我(%s): %s", people->name, input->value);
                
                deleteString(message);
                deleteString(input);
            }

            if (FD_ISSET(people->socket.socket, &fds)) {

                char _buffer[1000] = {0};

                int recv = tcpSocketRead(&people->socket, _buffer, sizeof(_buffer));

                if ((recv == 0 || recv < 0) && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) {
                    DEBUG_LOG("--- 数据接收异常，但不被视为远端关闭连接: %d ---", __func__, errno);
                    usleep(30000);
                    continue;
                } else if (recv <= 0) {
                    DEBUG_LOG("--- 数据接收异常，将视为远端关闭连接: %d ---", __func__, errno);
                    people->room->leave(people);
                    close(people->socket.socket);
                    return NULL;
                }

                String *buffer = createStringWith_cstr(_buffer);

                // INFO_LOG("收到新消息: %s", len ,buffer->value);
                // 消息解读: 格式 msg::::user::::value
                if (stringContains_cstr(buffer, "msg::::")) {
                    const char *sp = "::::";
                    StringList *words = createStringListWithSplits(buffer, sp);

                    int cnt = stringListLength(words);
                    INFO_LOG("%s:%s", 
                        stringListIndex(words, 1)->string->value,
                        stringListIndex(words, 2)->string->value); 
                    deleteStringList(words);
                }

                // 释放 buffer
                destroyString(buffer);
            }
        }
    }
    
}

// ----------------------------------------------------------------
bool createChatRoom(ChatRoom *room, int port) {
    room->peoples = NULL;
    return createTcpSocketServer(&room->socket, port);
}

bool connectChatRoomWithHost(ChatRoom *room, People *people, const char *host, int port) {
    if (createTcpSocketWithHostPort(&room->socket, host, port)) {
        if (socketConnect(&room->socket, &room->socket.address, sizeof(room->socket.address))) {
            people->socket = room->socket;
            people->room = room;
            char msg[100] = {"connect::::"};
            strcat(msg, people->name);
            tcpSocketWrite(&people->socket, msg, sizeof(msg));
            // tcpSocketRead(&tcp, msg, sizeof(msg));
            return true;
        }
    }
    return false;
}

// bool createPeopleConnectChatRoomWithHost(People *people, &room) {
    // return connectChatRoomWithHost(&people, host, port);
// }


// ----------------------------------------------------------------

// ---------------------------------------------------------------- System Call Back
void defaultNewChatRoom(ChatRoom *room) {
    INFO_LOG("--- 系统提示: 聊天室创建成功(当前%d人在线) --- ", listLength(room->peoples));
}

void defaultJoinChatRoom(People *people) {
    INFO_LOG("--- 系统提示: 加入聊天室(当前%d人在线) --- ", listLength(people->room->peoples));
}

void defaultLeveChatRoom(People *people) {
    INFO_LOG("--- 系统提示: 离开聊天室 ---");
}

void defaultNewChatRoomChannel(ChatRoomChannel *channel) {
    INFO_LOG("--- 系统提示: 频道(%s)创建成功 ---", channel->name);
}

void defaultJoinChatRoomChannel(ChatRoomChannel *channel) {
    INFO_LOG("--- 系统提示: 频道(%s)创建成功 ---", channel->name);
}

// ---------------------------------------------------------------- 
void workChatRoom(ChatRoom *room, newPeopleJoin newJoin, hasPeopleLeave hasLeave) {
    room->join = newJoin;
    room->leave = hasLeave;

    while (1) {
        People people;
        people.room = room;
        if (socketAccept(&room->socket, &people.socket)) {
            Thread thread;
            createThreadAfter(&thread, defaultChatRoomWorkThread, &people, (ThreadAfter)runThread);
        }
    }
}

void workPeople(People *people, newPeopleJoin join, hasPeopleLeave leave) {
    if (people->room == NULL) {
        people->room = malloc(sizeof(ChatRoom));
        people->room->join = defaultJoinChatRoom;
        people->room->leave = defaultLeveChatRoom;
        if (createTcpSocket(&people->socket)) {
            INFO_LOG("--- 系统提示: 初始化网络模块 ---");
        }
        INFO_LOG("--- 系统提示: %s 暂未连接到聊天室 ---", people->name);
    } else {
        people->socket = people->room->socket;
        people->room->join = join;
        people->room->leave = leave;
    }
    
    defaultPersonWorkThread(people);
};

// ---------------------------------------------------------------- Server
void defaultNewPeopleJoin(People *people) {
    INFO_LOG("--- 系统提示: 有成员加入聊天室 %s ---", people->name);
    people->room->peoples = listAppend(people->room->peoples, people);
}

void defaultHasPeopleLeave(People *people) {
    INFO_LOG("--- 系统提示: 有成员离开聊天室 %s ---", people->name);
    List *iter = NULL;
    List *newPeoples = NULL;
    list_foreach(iter, people->room->peoples) {
        if (iter->data != people) {
            newPeoples = listAppend(newPeoples, iter->data);
        }
    }
    destroyList(people->room->peoples);
    people->room->peoples = newPeoples;
}

void createDefaultRoom();
void createDefaultPerson();

#ifndef ChatRoomLib
int	main(int argc, char **argv)
{



    if (argc < 2) {
        printf("%s: [type port]|[type host port [name]]\n"
                "   - server: ./ChatRoom 0 8080\n"
                "   - client: ./ChatRoom 1 localhost 8080 zinface\n", argv[0]);
        exit(0);
    }
    // ./ChatRoom type port
    // ./ChatRoom type host port name
    int type = atoi(argv[1]);
    char name[20], host[20];

    ChatRoom room = {0};
    People people = { .room = &room, .name = "未知用户"};

    if (type == 0) { // Server
        if (createChatRoom(&room, atoi(argv[2]))) {
            INFO_LOG("--- 系统提示: 聊天室创建成功 ---");
        }
        
        workChatRoom(&room, defaultNewPeopleJoin, defaultHasPeopleLeave);
    } else { // Client
        
        if (argc > 4) { // 1 localhost 8080 zinface
            strcpy(people.name, argv[4]);
        }

        if (connectChatRoomWithHost(&room, &people, argv[2], atoi(argv[3]))) {
            workPeople(&people, defaultJoinChatRoom, defaultLeveChatRoom);
        }
    }
    return 0;
}

#endif  //